luci-mod-network: give wireless.js ES2016 treatment and refactor
authorPaul Donald <[email protected]>
Tue, 1 Apr 2025 14:43:05 +0000 (16:43 +0200)
committerPaul Donald <[email protected]>
Tue, 1 Apr 2025 14:43:05 +0000 (16:43 +0200)
Signed-off-by: Paul Donald <[email protected]>
modules/luci-mod-network/htdocs/luci-static/resources/view/network/wireless.js

index e76b2b7111e32a2a6d1f2e04e89cba7db4aafee9..8bdb62a46efac8cfa88f62f81fc23c1731dd6c7a 100644 (file)
 'require firewall';
 'require tools.widgets as widgets';
 
-var isReadonlyView = !L.hasViewPermission();
+const isReadonlyView = !L.hasViewPermission();
 
 function count_changes(section_id) {
-       var changes = ui.changes.changes, n = 0;
+       const changes = ui.changes.changes?.wireless;
+       if (!Array.isArray(changes)) return 0;
 
-       if (!L.isObject(changes))
-               return n;
-
-       if (Array.isArray(changes.wireless))
-               for (var i = 0; i < changes.wireless.length; i++)
-                       n += (changes.wireless[i][1] == section_id);
-
-       return n;
+       return changes.reduce((count, [, id]) => count + (id === section_id), 0);
 }
 
 function render_radio_badge(radioDev) {
@@ -35,32 +29,28 @@ function render_radio_badge(radioDev) {
 }
 
 function render_signal_badge(signalPercent, signalValue, noiseValue, wrap, mode) {
-       var icon, title, value;
-
-       if (signalPercent < 0)
-               icon = L.resource('icons/signal-none.png');
-       else if (signalPercent == 0)
-               icon = L.resource('icons/signal-0.png');
-       else if (signalPercent < 25)
-               icon = L.resource('icons/signal-0-25.png');
-       else if (signalPercent < 50)
-               icon = L.resource('icons/signal-25-50.png');
-       else if (signalPercent < 75)
-               icon = L.resource('icons/signal-50-75.png');
-       else
-               icon = L.resource('icons/signal-75-100.png');
-
-       if (signalValue != null && signalValue != 0) {
-               if (noiseValue != null && noiseValue != 0) {
-                       value = '%d/%d\xa0%s'.format(signalValue, noiseValue, _('dBm'));
-                       title = '%s: %d %s / %s: %d %s / %s %d'.format(
-                               _('Signal'), signalValue, _('dBm'),
-                               _('Noise'), noiseValue, _('dBm'),
-                               _('SNR'), signalValue - noiseValue);
+       let icon = L.resource('icons/signal-75-100.png'), title, value;
+
+       switch(true) {
+       case(signalPercent  < 0): icon = L.resource('icons/signal-none.png');   break;
+       case(signalPercent == 0): icon = L.resource('icons/signal-0.png');              break;
+       case(signalPercent < 25): icon = L.resource('icons/signal-0-25.png');   break;
+       case(signalPercent < 50): icon = L.resource('icons/signal-25-50.png');  break;
+       case(signalPercent < 75): icon = L.resource('icons/signal-50-75.png');  break;
+       }
+
+       if (signalValue) {
+               if (noiseValue) {
+                       value = `${signalValue}/${noiseValue}\xa0${_('dBm')}`;
+                       title = [
+                               `${_('Signal')}: ${signalValue} ${_('dBm')}`,
+                               `${_('Noise')}: ${noiseValue} ${_('dBm')}`,
+                               `${_('SNR')}: ${signalValue - noiseValue} ${_('dBm')}`
+                       ].filter(Boolean).join(' / ');
                }
                else {
-                       value = '%d\xa0%s'.format(signalValue, _('dBm'));
-                       title = '%s: %d %s'.format(_('Signal'), signalValue, _('dBm'));
+                       value = `${signalValue}\xa0${_('dBm')}`;
+                       title = `${_('Signal')} ${signalValue} ${_('dBm')}`;
                }
        }
        else if (signalPercent > -1) {
@@ -79,12 +69,12 @@ function render_signal_badge(signalPercent, signalValue, noiseValue, wrap, mode)
                                title = _('No RX signal');
                }
 
-               if (noiseValue != null && noiseValue != 0) {
-                       value = '---/%d\xa0%s'.format(noiseValue, _('dBm'));
-                       title = '%s / %s: %d %s'.format(title, _('Noise'), noiseValue, _('dBm'));
+               if (noiseValue) {
+                       value = `---/${noiseValue}\xa0${_('dBm')}`;
+                       title = `${title} / ${_('Noise')}: ${noiseValue} ${_('dBm')}`;
                }
                else {
-                       value = '---\xa0%s'.format(_('dBm'));
+                       value = `---\xa0${_('dBm')}`;
                }
        }
        else {
@@ -113,20 +103,20 @@ function render_network_badge(radioNet) {
 }
 
 function render_radio_status(radioDev, wifiNets) {
-       var name = radioDev.getI18n().replace(/ Wireless Controller .+$/, ''),
-           node = E('div', [ E('big', {}, E('strong', {}, name)), E('div') ]),
-           channel, frequency, bitrate;
-
-       for (var i = 0; i < wifiNets.length; i++) {
-               channel   = channel   || wifiNets[i].getChannel();
-               frequency = frequency || wifiNets[i].getFrequency();
-               bitrate   = bitrate   || wifiNets[i].getBitRate();
-       }
+       const name = radioDev.getI18n().replace(/ Wireless Controller .+$/, '');
+       const node = E('div', [ E('big', {}, E('strong', {}, name)), E('div') ]);
+       let channel, frequency, bitrate;
+
+       wifiNets.forEach(wifiNet => {
+               channel   = channel   ?? wifiNet.getChannel();
+               frequency = frequency ?? wifiNet.getFrequency();
+               bitrate   = bitrate   ?? wifiNet.getBitRate();
+       })
 
        if (radioDev.isUp())
                L.itemlist(node.lastElementChild, [
-                       _('Channel'), '%s (%s %s)'.format(channel || '?', frequency || '?', _('GHz')),
-                       _('Bitrate'), '%s %s'.format(bitrate || '?', _('Mbit/s'))
+                       _('Channel'), `${channel || '?'} (${frequency || '?'} ${_('GHz')})`,
+                       _('Bitrate'), `${bitrate || '?'} ${_('Mbit/s')}`
                ], ' | ');
        else
                node.lastElementChild.appendChild(E('em', _('Device is not active')));
@@ -135,14 +125,14 @@ function render_radio_status(radioDev, wifiNets) {
 }
 
 function render_network_status(radioNet) {
-       var mode = radioNet.getActiveMode(),
-           bssid = radioNet.getActiveBSSID(),
-           channel = radioNet.getChannel(),
-           disabled = (radioNet.get('disabled') == '1' || uci.get('wireless', radioNet.getWifiDeviceName(), 'disabled') == '1'),
-           is_assoc = (bssid && bssid != '00:00:00:00:00:00' && channel && mode != 'Unknown' && !disabled),
-           is_mesh = (radioNet.getMode() == 'mesh'),
-           changecount = count_changes(radioNet.getName()),
-           status_text = null;
+       const mode = radioNet.getActiveMode();
+       const bssid = radioNet.getActiveBSSID();
+       const channel = radioNet.getChannel();
+       const disabled = (radioNet.get('disabled') == '1' ?? uci.get('wireless', radioNet.getWifiDeviceName(), 'disabled') == '1');
+       const is_assoc = (bssid && bssid != '00:00:00:00:00:00' && channel && mode != 'Unknown' && !disabled);
+       const is_mesh = (radioNet.getMode() == 'mesh');
+       const changecount = count_changes(radioNet.getName());
+       let status_text = null;
 
        if (changecount)
                status_text = E('a', {
@@ -153,21 +143,21 @@ function render_network_status(radioNet) {
                status_text = E('em', disabled ? _('Wireless is disabled') : _('Wireless is not associated'));
 
        return L.itemlist(E('div'), [
-               is_mesh ? _('Mesh ID') : _('SSID'), (is_mesh ? radioNet.getMeshID() : radioNet.getSSID()) || '?',
+               is_mesh ? _('Mesh ID') : _('SSID'), (is_mesh ? radioNet.getMeshID() : radioNet.getSSID()) ?? '?',
                _('Mode'),       mode,
                _('BSSID'),      (!changecount && is_assoc) ? bssid : null,
-               _('Encryption'), (!changecount && is_assoc) ? radioNet.getActiveEncryption() || _('None') : null,
+               _('Encryption'), (!changecount && is_assoc) ? radioNet.getActiveEncryption() ?? _('None') : null,
                null,            status_text
        ], [ ' | ', E('br') ]);
 }
 
 function render_modal_status(node, radioNet) {
-       var mode = radioNet.getActiveMode(),
-           noise = radioNet.getNoise(),
-           bssid = radioNet.getActiveBSSID(),
-           channel = radioNet.getChannel(),
-           disabled = (radioNet.get('disabled') == '1'),
-           is_assoc = (bssid && bssid != '00:00:00:00:00:00' && channel && mode != 'Unknown' && !disabled);
+       const mode = radioNet.getActiveMode();
+       const noise = radioNet.getNoise();
+       const bssid = radioNet.getActiveBSSID();
+       const channel = radioNet.getChannel();
+       const disabled = (radioNet.get('disabled') == '1');
+       const is_assoc = (bssid && bssid != '00:00:00:00:00:00' && channel && mode != 'Unknown' && !disabled);
 
        if (node == null)
                node = E('span', { 'class': 'ifacebadge large', 'data-network': radioNet.getName() }, [ E('small'), E('span') ]);
@@ -178,14 +168,14 @@ function render_modal_status(node, radioNet) {
 
        L.itemlist(node.lastElementChild, [
                _('Mode'),       mode,
-               _('SSID'),       radioNet.getSSID() || '?',
+               _('SSID'),       radioNet.getSSID() ?? '?',
                _('BSSID'),      is_assoc ? bssid : null,
-               _('Encryption'), is_assoc ? radioNet.getActiveEncryption() || _('None') : null,
-               _('Channel'),    is_assoc ? '%d (%.3f %s)'.format(radioNet.getChannel(), radioNet.getFrequency() || 0, _('GHz')) : null,
-               _('Tx-Power'),   is_assoc ? '%d %s'.format(radioNet.getTXPower(), _('dBm')) : null,
-               _('Signal'),     is_assoc ? '%d %s'.format(radioNet.getSignal(), _('dBm')) : null,
-               _('Noise'),      (is_assoc && noise != null) ? '%d %s'.format(noise, _('dBm')) : null,
-               _('Bitrate'),    is_assoc ? '%.1f %s'.format(radioNet.getBitRate() || 0, _('Mbit/s')) : null,
+               _('Encryption'), is_assoc ? radioNet.getActiveEncryption() ?? _('None') : null,
+               _('Channel'),    is_assoc ? `${radioNet.getChannel()} (${radioNet.getFrequency() ?? 0} ${_('GHz')})` : null,
+               _('Tx-Power'),   is_assoc ? `${radioNet.getTXPower()} ${_('dBm')}` : null,
+               _('Signal'),     is_assoc ? `${radioNet.getSignal()} ${_('dBm')}` : null,
+               _('Noise'),      (is_assoc && noise != null) ? `${noise} ${_('dBm')}` : null,
+               _('Bitrate'),    is_assoc ? `${radioNet.getBitRate() ?? 0} ${_('Mbit/s')}` : null,
                _('Country'),    is_assoc ? radioNet.getCountryCode() : null
        ], [ ' | ', E('br'), E('br'), E('br'), E('br'), E('br'), ' | ', E('br'), ' | ' ]);
 
@@ -196,43 +186,48 @@ function render_modal_status(node, radioNet) {
 }
 
 function format_wifirate(rate) {
-       var s = '%.1f\xa0%s, %d\xa0%s'.format(rate.rate / 1000, _('Mbit/s'), rate.mhz, _('MHz')),
-           ht = rate.ht, vht = rate.vht,
-           mhz = rate.mhz, nss = rate.nss,
-           mcs = rate.mcs, sgi = rate.short_gi,
-           he = rate.he, he_gi = rate.he_gi,
-           he_dcm = rate.he_dcm,
-           eht = rate?.eht ?? false, eht_gi = rate?.eht_gi ?? 0,
-           eht_dcm = rate?.eht_dcm ?? 0;
-
-       if (ht || vht) {
-               if (vht) s += ', VHT-MCS\xa0%d'.format(mcs);
-               if (nss) s += ', VHT-NSS\xa0%d'.format(nss);
-               if (ht)  s += ', MCS\xa0%s'.format(mcs);
-               if (sgi) s += ', ' + _('Short GI').replace(/ /g, '\xa0');
-       }
-
-       if (he) {
-               s += ', HE-MCS\xa0%d'.format(mcs);
-               if (nss) s += ', HE-NSS\xa0%d'.format(nss);
-               if (he_gi) s += ', HE-GI\xa0%d'.format(he_gi);
-               if (he_dcm) s += ', HE-DCM\xa0%d'.format(he_dcm);
-       }
-
-       if (eht) {
-               s += ', EHT-MCS\xa0%d'.format(mcs);
-               if (nss) s += ', EHT-NSS\xa0%d'.format(nss);
-               if (eht_gi) s += ', EHT-GI\xa0%d'.format(eht_gi);
-               if (eht_dcm) s += ', EHT-DCM\xa0%d'.format(eht_dcm);
-       }
+       let s = `${rate.rate / 1000}\xa0${_('Mbit/s')}, ${rate.mhz}\xa0${_('MHz')}`;
+       const ht = rate.ht;
+       const vht = rate.vht;
+       const mhz = rate.mhz;
+       const nss = rate.nss;
+       const mcs = rate.mcs;
+       const sgi = rate.short_gi;
+       const he = rate.he;
+       const he_gi = rate.he_gi;
+       const he_dcm = rate.he_dcm;
+       const eht = rate?.eht ?? false;
+       const eht_gi = rate?.eht_gi ?? 0;
+       const eht_dcm = rate?.eht_dcm ?? 0;
+
+       if (ht ?? vht) s += [
+               vht && `, VHT-MCS\xa0${$mcs}`,
+               nss && `VHT-NSS\xa0${nss}`,
+               ht  && `MCS\xa0${mcs}`,
+               sgi && _('Short GI').replace(/ /g, '\xa0')
+       ].filter(Boolean).join(', ');
+
+       if (he) s += [
+               `, HE-MCS\xa0${mcs}`,
+               nss    && `HE-NSS\xa0${nss}`,
+               he_gi  && `HE-GI\xa0${he_gi}`,
+               he_dcm && `HE-DCM\xa0${he_dcm}`
+       ].filter(Boolean).join(', ');
+
+       if (eht) s += [
+               `, EHT-MCS\xa0${mcs}`,
+               nss    && `EHT-NSS\xa0${nss}`,
+               he_gi  && `EHT-GI\xa0${eht_gi}`,
+               he_dcm && `EHT-DCM\xa0${eht_dcm}`
+       ].filter(Boolean).join(', ');
 
        return s;
 }
 
 function radio_restart(id, ev) {
-       var row = document.querySelector('.cbi-section-table-row[data-sid="%s"]'.format(id)),
-           dsc = row.querySelector('[data-name="_stat"] > div'),
-           btn = row.querySelector('.cbi-section-actions button');
+       const row = document.querySelector('.cbi-section-table-row[data-sid="%s"]'.format(id));
+       const dsc = row.querySelector('[data-name="_stat"] > div');
+       const btn = row.querySelector('.cbi-section-actions button');
 
        btn.blur();
        btn.classList.add('spinning');
@@ -243,8 +238,8 @@ function radio_restart(id, ev) {
 }
 
 function network_updown(id, map, ev) {
-       var radio = uci.get('wireless', id, 'device'),
-           disabled = (uci.get('wireless', id, 'disabled') == '1') ||
+       const radio = uci.get('wireless', id, 'device');
+       const disabled = (uci.get('wireless', id, 'disabled') == '1') ||
                       (uci.get('wireless', radio, 'disabled') == '1');
 
        if (disabled) {
@@ -254,15 +249,13 @@ function network_updown(id, map, ev) {
        else {
                uci.set('wireless', id, 'disabled', '1');
 
-               var all_networks_disabled = true,
-                   wifi_ifaces = uci.sections('wireless', 'wifi-iface');
+               let all_networks_disabled = true;
+               const wifi_ifaces = uci.sections('wireless', 'wifi-iface');
 
-               for (var i = 0; i < wifi_ifaces.length; i++) {
-                       if (wifi_ifaces[i].device == radio && wifi_ifaces[i].disabled != '1') {
+               wifi_ifaces.forEach(wifi_iface => {
+                       if (wifi_iface.device == radio && wifi_iface.disabled != '1')
                                all_networks_disabled = false;
-                               break;
-                       }
-               }
+               })
 
                if (all_networks_disabled)
                        uci.set('wireless', radio, 'disabled', '1');
@@ -274,7 +267,7 @@ function network_updown(id, map, ev) {
 }
 
 function next_free_sid(offset) {
-       var sid = 'wifinet' + offset;
+       let sid = 'wifinet' + offset;
 
        while (uci.get('wireless', sid))
                sid = 'wifinet' + (++offset);
@@ -283,28 +276,15 @@ function next_free_sid(offset) {
 }
 
 function add_dependency_permutations(o, deps) {
-       var res = null;
-
-       for (var key in deps) {
-               if (!deps.hasOwnProperty(key) || !Array.isArray(deps[key]))
-                       continue;
+       let res = [{}];
 
-               var list = deps[key],
-                   tmp = [];
+       Object.entries(deps).forEach(([key, list]) => {
+               if (!Array.isArray(list)) return;
 
-               for (var j = 0; j < list.length; j++) {
-                       for (var k = 0; k < (res ? res.length : 1); k++) {
-                               var item = (res ? Object.assign({}, res[k]) : {});
-                               item[key] = list[j];
-                               tmp.push(item);
-                       }
-               }
-
-               res = tmp;
-       }
+               res = list.flatMap(value => res.map(item => ({ ...item, [key]: value })));
+       });
 
-       for (var i = 0; i < (res ? res.length : 0); i++)
-               o.depends(res[i]);
+       res.forEach(dep => o.depends(dep));
 }
 
 // Define a class CBIWifiFrequencyValue that extends form.Value
@@ -329,30 +309,28 @@ var CBIWifiFrequencyValue = form.Value.extend({
                                '6g': L.hasSystemFeature('hostapd', 'acs') ? [ 'auto', 'auto', { available: true } ] : [],
                                '60g': []
                        };
+                       const wifidevs = data[0];
+                       const freqlist = data[1];
 
-                       for (var i = 0; i < data[1].length; i++) {
-                               if (!data[1][i].band)
-                                       continue;
+                       freqlist.forEach(freq => {
+                               if (!freq.band)
+                                       return;
 
-                               var band = '%dg'.format(data[1][i].band),
-                                   available = true;
-
-
-                               if (data[1][i].restricted && data[1][i].no_ir)
-                                       available = false;
+                               const band = '%dg'.format(freq.band);
+                               const available = (freq.restricted && freq.no_ir) ? false: true;
 
                                this.channels[band].push(
-                                       data[1][i].channel,
-                                       '%d (%d Mhz)'.format(data[1][i].channel, data[1][i].mhz),
+                                       freq.channel,
+                                       '%d (%d Mhz)'.format(freq.channel, freq.mhz),
                                        {
                                                available: available,
-                                               no_outdoor: data[1][i].no_outdoor
+                                               no_outdoor: freq.no_outdoor
                                        }
                                        
                                );
-                       }
+                       });
 
-                       var hwmodelist = L.toArray(data[0] ? data[0].getHWModes() : null)
+                       const hwmodelist = L.toArray(wifidevs ? wifidevs.getHWModes() : null)
                                .reduce(function(o, v) { o[v] = true; return o }, {});
 
                        // Define supported modes
@@ -365,7 +343,7 @@ var CBIWifiFrequencyValue = form.Value.extend({
                        ];
 
                        // Create a list of HT modes based on device capabilities
-                       var htmodelist = L.toArray(data[0] ? data[0].getHTModes() : null)
+                       const htmodelist = L.toArray(wifidevs ? wifidevs.getHTModes() : null)
                                .reduce(function(o, v) { o[v] = true; return o }, {});
 
                        this.htmodes = {
@@ -429,15 +407,13 @@ var CBIWifiFrequencyValue = form.Value.extend({
                if (sel.vals)
                        sel.vals.selected = sel.selectedIndex;
 
-               while (sel.options[0])
-                       sel.remove(0);
+               sel.options.length = 0;
 
-               for (var i = 0; vals && i < vals.length; i += 3)
-                       if (vals[i+2] && vals[i+2].available)
-                               sel.add(E('option', { value: vals[i+0] }, [ vals[i+1] ]));
+               for (let i = 0; vals && i < vals.length; i += 3)
+                       if (vals[i+2]?.available)
+                               sel.add(E('option', { value: vals[i] }, [ vals[i+1] ]));
 
-               if (vals && !isNaN(vals.selected))
-                       sel.selectedIndex = vals.selected;
+               if (Number.isInteger(vals?.selected)) sel.selectedIndex = vals.selected;
 
                sel.parentNode.style.display = (sel.options.length <= 1) ? 'none' : '';
                sel.vals = vals;
@@ -449,15 +425,15 @@ var CBIWifiFrequencyValue = form.Value.extend({
        },
 
        toggleWifiHTMode: function(elem) {
-               var mode = elem.querySelector('.mode');
-               var bwdt = elem.querySelector('.htmode');
+               const mode = elem.querySelector('.mode');
+               const bwdt = elem.querySelector('.htmode');
 
                this.setValues(bwdt, this.htmodes[mode.value]);
        },
 
        toggleWifiBand: function(elem) {
-               var mode = elem.querySelector('.mode');
-               var band = elem.querySelector('.band');
+               const mode = elem.querySelector('.mode');
+               const band = elem.querySelector('.band');
 
                this.setValues(band, this.bands[mode.value]);
                this.toggleWifiChannel(elem);
@@ -466,25 +442,21 @@ var CBIWifiFrequencyValue = form.Value.extend({
        },
 
        checkWifiChannelRestriction: function(elem) {
-               var band = elem.querySelector('.band'),
-                    chan = elem.querySelector('.channel'),
-                    restricted_chan = elem.querySelector('.restricted_channel'),
-                    channels = this.channels[band.value],
-                    no_outdoor;
+               const band = elem.querySelector('.band');
+               const chan = elem.querySelector('.channel');
+               const restricted_chan = elem.querySelector('.restricted_channel');
+               const channels = this.channels[band.value];
 
                if (chan.selectedIndex < 0)
                        return;
 
-               no_outdoor = channels[(chan.selectedIndex*3)+2].no_outdoor;
-               if (no_outdoor)
-                       restricted_chan.style.display = '';
-               else
-                       restricted_chan.style.display = 'none';
+               const no_outdoor = channels[(chan.selectedIndex*3)+2].no_outdoor;
+               restricted_chan.style.display = no_outdoor ? '': 'none';
        },
 
        toggleWifiChannel: function(elem) {
-               var band = elem.querySelector('.band');
-               var chan = elem.querySelector('.channel');
+               const band = elem.querySelector('.band');
+               const chan = elem.querySelector('.channel');
 
                this.setValues(chan, this.channels[band.value]);
 
@@ -493,14 +465,14 @@ var CBIWifiFrequencyValue = form.Value.extend({
        },
 
        setInitialValues: function(section_id, elem) {
-               var mode = elem.querySelector('.mode'),
-                   band = elem.querySelector('.band'),
-                   chan = elem.querySelector('.channel'),
-                   bwdt = elem.querySelector('.htmode'),
-                   htval = uci.get('wireless', section_id, 'htmode'),
-                   hwval = uci.get('wireless', section_id, 'hwmode'),
-                   chval = uci.get('wireless', section_id, 'channel'),
-                   bandval = uci.get('wireless', section_id, 'band');
+               const mode = elem.querySelector('.mode');
+               const band = elem.querySelector('.band');
+               const chan = elem.querySelector('.channel');
+               const bwdt = elem.querySelector('.htmode');
+               const htval = uci.get('wireless', section_id, 'htmode');
+               const hwval = uci.get('wireless', section_id, 'hwmode');
+               const chval = uci.get('wireless', section_id, 'channel');
+               const bandval = uci.get('wireless', section_id, 'band');
 
                this.setValues(mode, this.modes);
 
@@ -521,10 +493,7 @@ var CBIWifiFrequencyValue = form.Value.extend({
                if (hwval != null) {
                        this.useBandOption = false;
 
-                       if (/a/.test(hwval))
-                               band.value = '5g';
-                       else
-                               band.value = '2g';
+                       band.value = /a/.test(hwval) ? '5g': '2g';
                }
                else {
                        this.useBandOption = true;
@@ -535,7 +504,7 @@ var CBIWifiFrequencyValue = form.Value.extend({
                this.toggleWifiBand(elem);
 
                bwdt.value = htval;
-               chan.value = chval || (chan.options[0] ? chan.options[0].value : 'auto');
+               chan.value = chval ?? (chan.options[0] ? chan.options[0].value : 'auto');
 
                this.checkWifiChannelRestriction(elem);
 
@@ -543,7 +512,7 @@ var CBIWifiFrequencyValue = form.Value.extend({
        },
 
        renderWidget: function(section_id, option_index, cfgvalue) {
-               var elem = E('div');
+               const elem = E('div');
 
                dom.content(elem, [
                        E('div', { 'class' : 'restricted_channel', 'style': 'display:none'}, [
@@ -600,7 +569,7 @@ var CBIWifiFrequencyValue = form.Value.extend({
        },
 
        formvalue: function(section_id) {
-               var node = this.map.findElement('data-field', this.cbid(section_id));
+               const node = this.map.findElement('data-field', this.cbid(section_id));
 
                return [
                    node.querySelector('.htmode').value,
@@ -612,9 +581,8 @@ var CBIWifiFrequencyValue = form.Value.extend({
        write: function(section_id, value) {
                uci.set('wireless', section_id, 'htmode', value[0] || null);
 
-               if (this.useBandOption)
-                       uci.set('wireless', section_id, 'band', value[1]);
-               else
+               this.useBandOption ?
+                       uci.set('wireless', section_id, 'band', value[1]) : 
                        uci.set('wireless', section_id, 'hwmode', (value[1] == '2g') ? '11g' : '11a');
 
                uci.set('wireless', section_id, 'channel', value[2]);
@@ -636,21 +604,22 @@ var CBIWifiTxPowerValue = form.ListValue.extend({
 
                        this.value('', _('driver default'));
 
-                       for (var i = 0; i < pwrlist.length; i++)
-                               this.value(pwrlist[i].dbm, '%d dBm (%d mW)'.format(pwrlist[i].dbm, pwrlist[i].mw));
+                       for (let p of pwrlist)
+                               this.value(p.dbm, `${p.dbm} dBm (${p.mw} mW)`);
 
                        return form.ListValue.prototype.load.apply(this, [section_id]);
                }, this));
        },
 
        renderWidget: function(section_id, option_index, cfgvalue) {
-               var widget = form.ListValue.prototype.renderWidget.apply(this, [section_id, option_index, cfgvalue]);
-                   widget.firstElementChild.style.width = 'auto';
+               const widget = form.ListValue.prototype.renderWidget.apply(this, [section_id, option_index, cfgvalue]);
+
+               widget.firstElementChild.style.width = 'auto';
 
                dom.append(widget, E('span', [
                        ' - ', _('Current power'), ': ',
-                       E('span', [ this.powerval != null ? '%d dBm'.format(this.powerval) : E('em', _('unknown')) ]),
-                       this.poweroff ? ' + %d dB offset = %s dBm'.format(this.poweroff, this.powerval != null ? this.powerval + this.poweroff : '?') : ''
+                       E('span', [ this.powerval != null ? `${this.powerval} dBm` : E('em', _('unknown')) ]),
+                       this.poweroff ? ` + ${this.poweroff} dB offset = ${this.powerval != null ? this.powerval + this.poweroff : '?'} dBm` : ''
                ]));
 
                return widget;
@@ -670,8 +639,8 @@ var CBIWifiCountryValue = form.Value.extend({
                        if (Array.isArray(countrylist) && countrylist.length > 0) {
                                this.value('', _('driver default'));
 
-                               for (var i = 0; i < countrylist.length; i++)
-                                       this.value(countrylist[i].iso3166, '%s - %s'.format(countrylist[i].iso3166, countrylist[i].country));
+                               for (let c of countrylist)
+                                       this.value(c.iso3166, `${c.iso3166} - ${c.country}`);
                        }
 
                        return form.Value.prototype.load.apply(this, [section_id]);
@@ -686,23 +655,24 @@ var CBIWifiCountryValue = form.Value.extend({
        },
 
        renderWidget: function(section_id, option_index, cfgvalue) {
-               var typeClass = (this.keylist && this.keylist.length) ? form.ListValue : form.Value;
+               const typeClass = (this.keylist && this.keylist.length) ? form.ListValue : form.Value;
                return typeClass.prototype.renderWidget.apply(this, [section_id, option_index, cfgvalue]);
        }
 });
 
 return view.extend({
        poll_status: function(map, data) {
-               var rows = map.querySelectorAll('.cbi-section-table-row[data-sid]');
-
-               for (var i = 0; i < rows.length; i++) {
-                       var section_id = rows[i].getAttribute('data-sid'),
-                           radioDev = data[1].filter(function(d) { return d.getName() == section_id })[0],
-                           radioNet = data[2].filter(function(n) { return n.getName() == section_id })[0],
-                           badge = rows[i].querySelector('[data-name="_badge"] > div'),
-                           stat = rows[i].querySelector('[data-name="_stat"]'),
-                           btns = rows[i].querySelectorAll('.cbi-section-actions button'),
-                           busy = btns[0].classList.contains('spinning') || btns[1].classList.contains('spinning') || btns[2].classList.contains('spinning');
+               const rows = map.querySelectorAll('.cbi-section-table-row[data-sid]');
+               let stat;
+
+               rows.forEach(row => {
+                       const section_id = row.getAttribute('data-sid');
+                       const radioDev = data[1].filter(function(d) { return d.getName() == section_id })[0];
+                       const radioNet = data[2].filter(function(n) { return n.getName() == section_id })[0];
+                       const badge = row.querySelector('[data-name="_badge"] > div');
+                       const stat = row.querySelector('[data-name="_stat"]');
+                       const btns = row.querySelectorAll('.cbi-section-actions button');
+                       const busy = btns[0].classList.contains('spinning') || btns[1].classList.contains('spinning') || btns[2].classList.contains('spinning');
 
                        if (radioDev) {
                                dom.content(badge, render_radio_badge(radioDev));
@@ -719,28 +689,30 @@ return view.extend({
                        btns[0].disabled = isReadonlyView || busy;
                        btns[1].disabled = (isReadonlyView && radioDev) || busy;
                        btns[2].disabled = isReadonlyView || busy;
-               }
+               });
 
-               var table = document.querySelector('#wifi_assoclist_table'),
-                   hosts = data[0],
-                   trows = [];
+               const table = document.querySelector('#wifi_assoclist_table');
+               const hosts = data[0];
+               let trows = [];
+               const radios = data[3];
+               const zones = data[4]
 
-               for (var i = 0; i < data[3].length; i++) {
-                       var bss = data[3][i],
-                           name = hosts.getHostnameByMACAddr(bss.mac),
-                           ipv4 = hosts.getIPAddrByMACAddr(bss.mac),
-                           ipv6 = hosts.getIP6AddrByMACAddr(bss.mac);
+               radios.forEach(zone => {
+                       const bss = zone;
+                       const name = hosts.getHostnameByMACAddr(bss.mac);
+                       const ipv4 = hosts.getIPAddrByMACAddr(bss.mac);
+                       const ipv6 = hosts.getIP6AddrByMACAddr(bss.mac);
 
-                       var hint;
+                       let hint;
 
                        if (name && ipv4 && ipv6)
-                               hint = '%s <span class="hide-xs">(%s, %s)</span>'.format(name, ipv4, ipv6);
-                       else if (name && (ipv4 || ipv6))
-                               hint = '%s <span class="hide-xs">(%s)</span>'.format(name, ipv4 || ipv6);
+                               hint = `${name} <span class="hide-xs">(${ipv4}, ${ipv6})</span>`;
+                       else if (name && (ipv4 ?? ipv6))
+                               hint = `${name} <span class="hide-xs">(${ipv4 || ipv6})</span>`;
                        else
                                hint = name || ipv4 || ipv6 || '?';
 
-                       var row = [
+                       let row = [
                                E('span', {
                                        'class': 'ifacebadge',
                                        'data-ifname': bss.network.getIfname(),
@@ -751,8 +723,8 @@ return view.extend({
                                                'title': bss.radio.getI18n()
                                        }),
                                        E('span', [
-                                               ' %s '.format(bss.network.getShortName()),
-                                               E('small', '(%s)'.format(bss.network.getIfname()))
+                                               ` ${bss.network.getShortName()} `,
+                                               E('small', `(${bss.network.getIfname()})`)
                                        ])
                                ]),
                                bss.mac,
@@ -765,11 +737,10 @@ return view.extend({
                                ])
                        ];
 
-                       var zones = data[4];
                        if (bss.vlan) {
-                               var desc = bss.vlan.getI18n();
-                               var vlan_network = bss.vlan.getNetwork();
-                               var vlan_zone;
+                               const desc = bss.vlan.getI18n();
+                               const vlan_network = bss.vlan.getNetwork();
+                               let vlan_zone;
 
                                if (vlan_network && zones)
                                        for (let zone of zones)
@@ -806,14 +777,14 @@ return view.extend({
                        }
 
                        trows.push(row);
-               }
+               })
 
                cbi_update_table(table, trows, E('em', _('No information available')));
 
-               var stat = document.querySelector('.cbi-modal [data-name="_wifistat_modal"] .ifacebadge.large');
+               const status = document.querySelector('.cbi-modal [data-name="_wifistat_modal"] .ifacebadge.large');
 
-               if (stat)
-                       render_modal_status(stat, data[2].filter(function(n) { return n.getName() == stat.getAttribute('data-network') })[0]);
+               if (status)
+                       render_modal_status(status, data[2].filter(function(n) { return n.getName() == status.getAttribute('data-network') })[0]);
 
                return network.flushCache();
        },
@@ -828,13 +799,7 @@ return view.extend({
        },
 
        checkAnonymousSections: function() {
-               var wifiIfaces = uci.sections('wireless', 'wifi-iface');
-
-               for (var i = 0; i < wifiIfaces.length; i++)
-                       if (wifiIfaces[i]['.anonymous'])
-                               return true;
-
-               return false;
+               return uci.sections('wireless', 'wifi-iface').some(iface => iface['.anonymous']);
        },
 
        callUciRename: rpc.declare({
@@ -851,19 +816,17 @@ return view.extend({
        },
 
        handleMigration: function(ev) {
-               var wifiIfaces = uci.sections('wireless', 'wifi-iface'),
-                   id_offset = 0,
-                   tasks = [];
-
-               for (var i = 0; i < wifiIfaces.length; i++) {
-                       if (!wifiIfaces[i]['.anonymous'])
-                               continue;
-
-                       var new_name = next_free_sid(id_offset);
-
-                       tasks.push(this.callUciRename('wireless', wifiIfaces[i]['.name'], new_name));
-                       id_offset = +new_name.substring(7) + 1;
-               }
+               const wifiIfaces = uci.sections('wireless', 'wifi-iface');
+               let id_offset = 0;
+               const tasks = [];
+
+               wifiIfaces.forEach((iface) => {
+                       if (iface['.anonymous']) {
+                               const new_name = next_free_sid(id_offset);
+                               tasks.push(this.callUciRename('wireless', iface['.name'], new_name));
+                               id_offset = parseInt(new_name.substring(7), 10) + 1;
+                   }
+               });
 
                return Promise.all(tasks)
                        .then(L.bind(ui.changes.init, ui.changes))
@@ -883,7 +846,7 @@ return view.extend({
        },
 
        renderOverview: function(zones) {
-               var m, s, o;
+               let m, s, o;
 
                m = new form.Map('wireless');
                m.chain('network');
@@ -899,45 +862,48 @@ return view.extend({
                                        return a.getName() > b.getName();
                                });
 
-                               var tasks = [];
+                               const tasks = [];
 
-                               for (var i = 0; i < radios.length; i++)
-                                       tasks.push(radios[i].getWifiNetworks());
+                               radios.forEach(radio => {
+                                       tasks.push(radio.getWifiNetworks());
+                               })
 
                                return Promise.all(tasks);
                        }, this)).then(L.bind(function(data) {
                                this.wifis = [];
 
-                               for (var i = 0; i < data.length; i++)
-                                       this.wifis.push.apply(this.wifis, data[i]);
+                               data.forEach(d => {
+                                       this.wifis.push.apply(this.wifis, d);
+                               })
                        }, this));
                };
 
                s.cfgsections = function() {
-                       var rv = [];
+                       const rv = [];
 
-                       for (var i = 0; i < this.radios.length; i++) {
-                               rv.push(this.radios[i].getName());
+                       this.radios.forEach(radio => {
+                               rv.push(radio.getName());
 
-                               for (var j = 0; j < this.wifis.length; j++)
-                                       if (this.wifis[j].getWifiDeviceName() == this.radios[i].getName())
-                                               rv.push(this.wifis[j].getName());
-                       }
+                               this.wifis.forEach(wifi => {
+                                       if (wifi.getWifiDeviceName() == radio.getName())
+                                               rv.push(wifi.getName());
+                               });
+                       });
 
                        return rv;
                };
 
                s.modaltitle = function(section_id) {
-                       var radioNet = this.wifis.filter(function(w) { return w.getName() == section_id})[0];
+                       const radioNet = this.wifis.filter(function(w) { return w.getName() == section_id})[0];
                        return radioNet ? radioNet.getI18n() : _('Edit wireless network');
                };
 
                s.lookupRadioOrNetwork = function(section_id) {
-                       var radioDev = this.radios.filter(function(r) { return r.getName() == section_id })[0];
+                       const radioDev = this.radios.filter(function(r) { return r.getName() == section_id })[0];
                        if (radioDev)
                                return radioDev;
 
-                       var radioNet = this.wifis.filter(function(w) { return w.getName() == section_id })[0];
+                       const radioNet = this.wifis.filter(function(w) { return w.getName() == section_id })[0];
                        if (radioNet)
                                return radioNet;
 
@@ -945,7 +911,8 @@ return view.extend({
                };
 
                s.renderRowActions = function(section_id) {
-                       var inst = this.lookupRadioOrNetwork(section_id), btns;
+                       const inst = this.lookupRadioOrNetwork(section_id);
+                       let btns;
 
                        if (inst.getWifiNetworks) {
                                btns = [
@@ -967,7 +934,7 @@ return view.extend({
                                ];
                        }
                        else {
-                               var isDisabled = (inst.get('disabled') == '1' ||
+                               const isDisabled = (inst.get('disabled') == '1' ||
                                        uci.get('wireless', inst.getWifiDeviceName(), 'disabled') == '1');
 
                                btns = [
@@ -994,8 +961,8 @@ return view.extend({
 
                s.addModalOptions = function(s) {
                        return network.getWifiNetwork(s.section).then(function(radioNet) {
-                               var hwtype = uci.get('wireless', radioNet.getWifiDeviceName(), 'type');
-                               var o, ss;
+                               const hwtype = uci.get('wireless', radioNet.getWifiDeviceName(), 'type');
+                               let o, ss;
 
                                o = s.option(form.SectionValue, '_device', form.NamedSection, radioNet.getWifiDeviceName(), 'wifi-device', _('Device Configuration'));
                                o.modalonly = true;
@@ -1004,7 +971,7 @@ return view.extend({
                                ss.tab('general', _('General Setup'));
                                ss.tab('advanced', _('Advanced Settings'));
 
-                               var isDisabled = (radioNet.get('disabled') == '1' ||
+                               const isDisabled = (radioNet.get('disabled') == '1' ||
                                        uci.get('wireless', radioNet.getWifiDeviceName(), 'disabled') == 1);
 
                                o = ss.taboption('general', form.DummyValue, '_wifistat_modal', _('Status'));
@@ -1108,23 +1075,24 @@ return view.extend({
                                o.novirtual = true;
                                o.write = function(section_id, value) {
                                        return network.getDevice(section_id).then(L.bind(function(dev) {
-                                               var old_networks = dev.getNetworks().reduce(function(o, v) { o[v.getName()] = v; return o }, {}),
-                                                   new_networks = {},
-                                                   values = L.toArray(value),
-                                                   tasks = [];
+                                               const old_networks = dev.getNetworks().reduce(function(o, v) { o[v.getName()] = v; return o }, {});
+                                               const new_networks = {};
+                                               const values = L.toArray(value);
+                                               const tasks = [];
 
-                                               for (var i = 0; i < values.length; i++) {
-                                                       new_networks[values[i]] = true;
+                                               values.forEach(value => {
 
-                                                       if (old_networks[values[i]])
-                                                               continue;
+                                                       new_networks[value] = true;
 
-                                                       tasks.push(network.getNetwork(values[i]).then(L.bind(function(name, net) {
+                                                       if (old_networks[value])
+                                                               return;
+
+                                                       tasks.push(network.getNetwork(value).then(L.bind(function(name, net) {
                                                                return net || network.addNetwork(name, { proto: 'none' });
-                                                       }, this, values[i])).then(L.bind(function(dev, net) {
+                                                       }, this, value)).then(L.bind(function(dev, net) {
                                                                if (net) {
                                                                        if (!net.isEmpty()) {
-                                                                               var target_dev = net.getDevice();
+                                                                               const target_dev = net.getDevice();
 
                                                                                /* Resolve parent interface of vlan */
                                                                                while (target_dev && target_dev.getType() == 'vlan')
@@ -1137,9 +1105,9 @@ return view.extend({
                                                                        net.addDevice(dev);
                                                                }
                                                        }, this, dev)));
-                                               }
+                                               });
 
-                                               for (var name in old_networks)
+                                               for (let name in old_networks)
                                                        if (!new_networks[name])
                                                                tasks.push(network.getNetwork(name).then(L.bind(function(dev, net) {
                                                                        if (net)
@@ -1150,10 +1118,10 @@ return view.extend({
                                        }, this));
                                };
 
+                               let encr;
                                if (hwtype == 'mac80211') {
-                                       var mode = ss.children[0],
-                                           bssid = ss.children[5],
-                                           encr;
+                                       const mode = ss.children[0];
+                                       const bssid = ss.children[5];
 
                                        mode.value('mesh', '802.11s');
                                        mode.value('ahdemo', _('Pseudo Ad-Hoc (ahdemo)'));
@@ -1208,8 +1176,8 @@ return view.extend({
                                        };
 
                                        mode.cfgvalue = function(section_id) {
-                                               var mode = uci.get('wireless', section_id, 'mode'),
-                                                   wds = uci.get('wireless', section_id, 'wds');
+                                               const mode = uci.get('wireless', section_id, 'mode');
+                                               const wds = uci.get('wireless', section_id, 'wds');
 
                                                if (mode == 'ap' && wds)
                                                        return 'ap-wds';
@@ -1246,7 +1214,7 @@ return view.extend({
                                        if (/^radio\d+\.network/.test(o.placeholder))
                                                o.placeholder = '';
 
-                                       var macaddr = uci.get('wireless', radioNet.getName(), 'macaddr');
+                                       const macaddr = uci.get('wireless', radioNet.getName(), 'macaddr');
                                        o = ss.taboption('advanced', form.Value, 'macaddr', _('MAC address'), _('Override default MAC address - the range of usable addresses might be limited by the driver'));
                                        o.value('', _('driver default (%s)').format(!macaddr ? radioNet.getActiveBSSID() : _('no override')));
                                        o.value('random', _('randomly generated'));
@@ -1294,7 +1262,7 @@ return view.extend({
                                o.depends('mode', 'mesh');
 
                                o.cfgvalue = function(section_id) {
-                                       var v = String(uci.get('wireless', section_id, 'encryption'));
+                                       const v = String(uci.get('wireless', section_id, 'encryption'));
                                        if (v == 'wep')
                                                return 'wep-open';
                                        else if (v.match(/\+/))
@@ -1303,8 +1271,8 @@ return view.extend({
                                };
 
                                o.write = function(section_id, value) {
-                                       var e = this.section.children.filter(function(o) { return o.option == 'encryption' })[0].formvalue(section_id),
-                                           co = this.section.children.filter(function(o) { return o.option == 'cipher' })[0], c = co.formvalue(section_id);
+                                       let e = this.section.children.filter(function(o) { return o.option == 'encryption' })[0].formvalue(section_id);
+                                       const co = this.section.children.filter(function(o) { return o.option == 'cipher' })[0], c = co.formvalue(section_id);
 
                                        if (value == 'wpa' || value == 'wpa2' || value == 'wpa3' || value == 'wpa3-mixed' || value == 'wpa3-192')
                                                uci.unset('wireless', section_id, 'key');
@@ -1335,7 +1303,7 @@ return view.extend({
                                o.write = ss.children.filter(function(o) { return o.option == 'encryption' })[0].write;
 
                                o.cfgvalue = function(section_id) {
-                                       var v = String(uci.get('wireless', section_id, 'encryption'));
+                                       let v = String(uci.get('wireless', section_id, 'encryption'));
                                        if (v.match(/\+/)) {
                                                v = v.replace(/^[^+]+\+/, '');
                                                if (v == 'aes')
@@ -1347,31 +1315,31 @@ return view.extend({
                                };
 
 
-                               var crypto_modes = [];
+                               const crypto_modes = [];
 
                                if (hwtype == 'mac80211') {
-                                       var has_supplicant = L.hasSystemFeature('wpasupplicant'),
-                                           has_hostapd = L.hasSystemFeature('hostapd');
+                                       const has_supplicant = L.hasSystemFeature('wpasupplicant');
+                                       const has_hostapd = L.hasSystemFeature('hostapd');
 
                                        // Probe EAP support
-                                       var has_ap_eap = L.hasSystemFeature('hostapd', 'eap'),
-                                           has_sta_eap = L.hasSystemFeature('wpasupplicant', 'eap');
+                                       const has_ap_eap = L.hasSystemFeature('hostapd', 'eap');
+                                       const has_sta_eap = L.hasSystemFeature('wpasupplicant', 'eap');
 
                                        // Probe SAE support
-                                       var has_ap_sae = L.hasSystemFeature('hostapd', 'sae'),
-                                           has_sta_sae = L.hasSystemFeature('wpasupplicant', 'sae');
+                                       const has_ap_sae = L.hasSystemFeature('hostapd', 'sae');
+                                       const has_sta_sae = L.hasSystemFeature('wpasupplicant', 'sae');
 
                                        // Probe OWE support
-                                       var has_ap_owe = L.hasSystemFeature('hostapd', 'owe'),
-                                           has_sta_owe = L.hasSystemFeature('wpasupplicant', 'owe');
+                                       const has_ap_owe = L.hasSystemFeature('hostapd', 'owe');
+                                       const has_sta_owe = L.hasSystemFeature('wpasupplicant', 'owe');
 
                                        // Probe Suite-B support
-                                       var has_ap_eap192 = L.hasSystemFeature('hostapd', 'suiteb192'),
-                                           has_sta_eap192 = L.hasSystemFeature('wpasupplicant', 'suiteb192');
+                                       const has_ap_eap192 = L.hasSystemFeature('hostapd', 'suiteb192');
+                                       const has_sta_eap192 = L.hasSystemFeature('wpasupplicant', 'suiteb192');
 
                                        // Probe WEP support
-                                       var has_ap_wep = L.hasSystemFeature('hostapd', 'wep'),
-                                           has_sta_wep = L.hasSystemFeature('wpasupplicant', 'wep');
+                                       const has_ap_wep = L.hasSystemFeature('hostapd', 'wep');
+                                       const has_sta_wep = L.hasSystemFeature('wpasupplicant', 'wep');
 
                                        if (has_hostapd || has_supplicant) {
                                                crypto_modes.push(['psk2',      'WPA2-PSK',                    35]);
@@ -1462,10 +1430,10 @@ return view.extend({
                                        encr.crypto_support['sta-wds'] = encr.crypto_support['sta'];
 
                                        encr.validate = function(section_id, value) {
-                                               var modeopt = this.section.children.filter(function(o) { return o.option == 'mode' })[0],
-                                                   modeval = modeopt.formvalue(section_id),
-                                                   modetitle = modeopt.vallist[modeopt.keylist.indexOf(modeval)],
-                                                   enctitle = this.vallist[this.keylist.indexOf(value)];
+                                               const modeopt = this.section.children.filter(function(o) { return o.option == 'mode' })[0];
+                                               const modeval = modeopt.formvalue(section_id);
+                                               const modetitle = modeopt.vallist[modeopt.keylist.indexOf(modeval)];
+                                               const enctitle = this.vallist[this.keylist.indexOf(value)];
 
                                                if (value == 'none')
                                                        return true;
@@ -1488,13 +1456,13 @@ return view.extend({
 
                                crypto_modes.sort(function(a, b) { return b[2] - a[2] });
 
-                               for (var i = 0; i < crypto_modes.length; i++) {
-                                       var security_level = (crypto_modes[i][2] >= 30) ? _('strong security')
-                                               : (crypto_modes[i][2] >= 20) ? _('medium security')
-                                                       : (crypto_modes[i][2] >= 10) ? _('weak security') : _('open network');
+                               crypto_modes.forEach(crypto_mode => {
+                                       const security_level = (crypto_mode[2] >= 30) ? _('strong security')
+                                               : (crypto_mode[2] >= 20) ? _('medium security')
+                                                       : (crypto_mode[2] >= 10) ? _('weak security') : _('open network');
 
-                                       encr.value(crypto_modes[i][0], '%s (%s)'.format(crypto_modes[i][1], security_level));
-                               }
+                                       encr.value(crypto_mode[0], '%s (%s)'.format(crypto_mode[1], security_level));
+                               });
 
 
                                o = ss.taboption('encryption', form.Flag, 'ppsk', _('Enable Private PSK (PPSK)'), _('Private Pre-Shared Key (PPSK) allows the use of different Pre-Shared Key for each STA MAC address. Private MAC PSKs are stored on the RADIUS server.'));
@@ -1536,7 +1504,7 @@ return view.extend({
                                o.password = true;
 
                                /* extra RADIUS settings start */
-                               var attr_validate = function(section_id, value) {
+                               const attr_validate = function(section_id, value) {
                                        if (!value)
                                                return true;
 
@@ -1546,7 +1514,7 @@ return view.extend({
                                        return true;
                                };
 
-                               var req_attr_syntax = _('Format:') + '<code>&lt;attr_id&gt;[:&lt;syntax:value&gt;]</code>' + '<br />' +
+                               const req_attr_syntax = _('Format:') + '<code>&lt;attr_id&gt;[:&lt;syntax:value&gt;]</code>' + '<br />' +
                                        '<code>syntax: s = %s; '.format(_('string (UTF-8)')) + 'd = %s; '.format(_('integer')) + 'x = %s</code>'.format(_('octet string'))
 
                                /* https://w1.fi/cgit/hostap/commit/?id=af35e7af7f8bb1ca9f0905b4074fb56a264aa12b */
@@ -1631,7 +1599,7 @@ return view.extend({
                                o.password = true;
 
                                o.cfgvalue = function(section_id) {
-                                       var key = uci.get('wireless', section_id, 'key');
+                                       const key = uci.get('wireless', section_id, 'key');
                                        return /^[1234]$/.test(key) ? null : key;
                                };
 
@@ -1653,7 +1621,7 @@ return view.extend({
                                o.value('4', _('Key #%d').format(4));
 
                                o.cfgvalue = function(section_id) {
-                                       var slot = +uci.get('wireless', section_id, 'key');
+                                       const slot = +uci.get('wireless', section_id, 'key');
                                        return (slot >= 1 && slot <= 4) ? String(slot) : '';
                                };
 
@@ -1661,7 +1629,7 @@ return view.extend({
                                        uci.set('wireless', section_id, 'key', value);
                                };
 
-                               for (var slot = 1; slot <= 4; slot++) {
+                               for (let slot = 1; slot <= 4; slot++) {
                                        o = ss.taboption('encryption', form.Value, 'key%d'.format(slot), _('Key #%d').format(slot));
                                        o.depends('encryption', 'wep-open');
                                        o.depends('encryption', 'wep-shared');
@@ -1679,7 +1647,7 @@ return view.extend({
 
                                if (hwtype == 'mac80211') {
                                        // Probe 802.11r support (and EAP support as a proxy for Openwrt)
-                                       var has_80211r = L.hasSystemFeature('hostapd', '11r') || L.hasSystemFeature('hostapd', 'eap');
+                                       const has_80211r = L.hasSystemFeature('hostapd', '11r') || L.hasSystemFeature('hostapd', 'eap');
 
                                        o = ss.taboption('roaming', form.Flag, 'ieee80211r', _('802.11r Fast Transition'), _('Enables fast roaming among access points that belong to the same Mobility Domain'));
                                        add_dependency_permutations(o, { mode: ['ap', 'ap-wds'], encryption: ['wpa2', 'wpa3', 'wpa3-mixed', , 'wpa3-192'] });
@@ -1767,7 +1735,7 @@ return view.extend({
                                                }
 
                                                //Pull current System TZ setting
-                                               var tz = uci.get('system', '@system[0]', 'timezone');
+                                               const tz = uci.get('system', '@system[0]', 'timezone');
                                                o = ss.taboption('roaming', form.Value, 'time_zone', _('Time zone'), _('802.11v: Local Time Zone Advertisement in management frames.'));
                                                o.value(tz);
                                                o.rmempty = true;
@@ -1848,8 +1816,8 @@ return view.extend({
                                        add_dependency_permutations(o, { mode: ['sta', 'sta-wds'], encryption: ['wpa', 'wpa2', 'wpa3', 'wpa3-mixed', 'wpa3-192'], eap_type: ['fast', 'peap', 'ttls'] });
 
                                        o.validate = function(section_id, value) {
-                                               var eo = this.section.children.filter(function(o) { return o.option == 'eap_type' })[0],
-                                                   ev = eo.formvalue(section_id);
+                                               const eo = this.section.children.filter(function(o) { return o.option == 'eap_type' })[0];
+                                               const ev = eo.formvalue(section_id);
 
                                                if (ev != 'ttls' && (value == 'PAP' || value == 'CHAP' || value == 'MSCHAP' || value == 'MSCHAPV2'))
                                                        return _('This authentication type is not applicable to the selected EAP method.');
@@ -1950,8 +1918,8 @@ return view.extend({
                                                        o.depends('ieee80211w', '2');
 
                                                        o.validate = function(section_id, value) {
-                                                               var modeopt = this.section.children.filter(function(o) { return o.option == 'mode' })[0],
-                                                               modeval = modeopt.formvalue(section_id);
+                                                               const modeopt = this.section.children.filter(function(o) { return o.option == 'mode' })[0];
+                                                               const modeval = modeopt.formvalue(section_id);
 
                                                                if ((value == '2') && ((modeval == 'sta') || (modeval == 'sta-wds'))) {
                                                                        return _('Workaround mode can only be used when acting as an access point.');
@@ -1986,7 +1954,7 @@ return view.extend({
                };
 
                s.handleScan = function(radioDev, ev) {
-                       var table = E('table', { 'class': 'table' }, [
+                       const table = E('table', { 'class': 'table' }, [
                                E('tr', { 'class': 'tr table-titles' }, [
                                        E('th', { 'class': 'th col-2 middle center' }, _('Signal')),
                                        E('th', { 'class': 'th col-4 middle left' }, _('SSID')),
@@ -1998,7 +1966,7 @@ return view.extend({
                                ])
                        ]);
 
-                       var stop = E('button', {
+                       const stop = E('button', {
                                'class': 'btn',
                                'click': L.bind(this.handleScanStartStop, this),
                                'style': 'display:none',
@@ -2007,7 +1975,7 @@ return view.extend({
 
                        cbi_update_table(table, [], E('em', { class: 'spinning' }, _('Starting wireless scan...')));
 
-                       var md = ui.showModal(_('Join Network: Wireless Scan'), [
+                       const md = ui.showModal(_('Join Network: Wireless Scan'), [
                                table,
                                E('div', { 'class': 'right' }, [
                                        stop,
@@ -2030,17 +1998,17 @@ return view.extend({
 
                s.handleScanRefresh = function(radioDev, scanCache, table, stop) {
                        return radioDev.getScanList().then(L.bind(function(results) {
-                               var rows = [];
+                               const rows = [];
 
-                               for (var i = 0; i < results.length; i++)
-                                       scanCache[results[i].bssid] = results[i];
+                               for (let r of results)
+                                       scanCache[r.bssid] = r;
 
-                               for (var k in scanCache)
+                               for (let k in scanCache)
                                        if (scanCache[k].stale)
                                                results.push(scanCache[k]);
 
                                results.sort(function(a, b) {
-                                       var diff = (b.quality - a.quality) || (a.channel - b.channel);
+                                       const diff = (b.quality - a.quality) || (a.channel - b.channel);
 
                                        if (diff)
                                                return diff;
@@ -2056,20 +2024,19 @@ return view.extend({
                                                return 1;
                                });
 
-                               for (var i = 0; i < results.length; i++) {
-                                       var res = results[i],
-                                           qv = res.quality || 0,
-                                           qm = res.quality_max || 0,
-                                           q = (qv > 0 && qm > 0) ? Math.floor((100 / qm) * qv) : 0,
-                                           s = res.stale ? 'opacity:0.5' : '';
+                               results.forEach(res => {
+                                       const qv = res?.quality ?? 0;
+                                       const qm = res?.quality_max ?? 0;
+                                       const q = (qv > 0 && qm > 0) ? Math.floor((100 / qm) * qv) : 0;
+                                       const s = res.stale ? 'opacity:0.5' : '';
 
                                        rows.push([
-                                               E('span', { 'style': s }, render_signal_badge(q, res.signal, res.noise)),
-                                               E('span', { 'style': s }, (res.ssid != null) ? '%h'.format(res.ssid) : E('em', _('hidden'))),
-                                               E('span', { 'style': s }, '%d'.format(res.channel)),
-                                               E('span', { 'style': s }, '%h'.format(res.mode)),
-                                               E('span', { 'style': s }, '%h'.format(res.bssid)),
-                                               E('span', { 'style': s }, '%h'.format(network.formatWifiEncryption(res.encryption))),
+                                               E('span', { 'style': s }, render_signal_badge(q, res?.signal, res?.noise)),
+                                               E('span', { 'style': s }, (res?.ssid != null) ? `${res?.ssid}` : E('em', _('hidden'))),
+                                               E('span', { 'style': s }, `${res?.channel}`),
+                                               E('span', { 'style': s }, `${res?.mode}`),
+                                               E('span', { 'style': s }, `${res?.bssid}`),
+                                               E('span', { 'style': s }, `${network.formatWifiEncryption(res?.encryption)}`),
                                                E('div', { 'class': 'right' }, E('button', {
                                                        'class': 'cbi-button cbi-button-action important',
                                                        'click': ui.createHandlerFn(this, 'handleJoin', radioDev, res)
@@ -2077,7 +2044,7 @@ return view.extend({
                                        ]);
 
                                        res.stale = true;
-                               }
+                               });
 
                                cbi_update_table(table, rows);
 
@@ -2088,7 +2055,7 @@ return view.extend({
                };
 
                s.handleScanStartStop = function(ev) {
-                       var btn = ev.currentTarget;
+                       const btn = ev.currentTarget;
 
                        if (btn.getAttribute('data-state') == 'stop') {
                                poll.remove(this.pollFn);
@@ -2105,7 +2072,7 @@ return view.extend({
                };
 
                s.handleScanAbort = function(ev) {
-                       var md = dom.parent(ev.target, 'div[aria-modal="true"]');
+                       const md = dom.parent(ev.target, 'div[aria-modal="true"]');
                        if (md) {
                                md.style.maxWidth = '';
                                md.style.maxHeight = '';
@@ -2118,48 +2085,48 @@ return view.extend({
                };
 
                s.handleJoinConfirm = function(radioDev, bss, form, ev) {
-                       var nameopt = L.toArray(form.lookupOption('name', '_new_'))[0],
-                           passopt = L.toArray(form.lookupOption('password', '_new_'))[0],
-                           ssidopt = L.toArray(form.lookupOption('ssid', '_new_'))[0],
-                           bssidopt = L.toArray(form.lookupOption('bssid', '_new_'))[0],
-                           zoneopt = L.toArray(form.lookupOption('zone', '_new_'))[0],
-                           replopt = L.toArray(form.lookupOption('replace', '_new_'))[0],
-                           nameval = (nameopt && nameopt.isValid('_new_')) ? nameopt.formvalue('_new_') : null,
-                           passval = (passopt && passopt.isValid('_new_')) ? passopt.formvalue('_new_') : null,
-                           ssidval = (ssidopt && ssidopt.isValid('_new_')) ? ssidopt.formvalue('_new_') : null,
-                           bssidval = (bssidopt && bssidopt.isValid('_new_')) ? bssidopt.formvalue('_new_') : null,
-                           zoneval = zoneopt ? zoneopt.formvalue('_new_') : null,
-                           enc = L.isObject(bss.encryption) ? bss.encryption : null,
-                           is_wep = (enc && Array.isArray(enc.wep)),
-                           is_psk = (enc && Array.isArray(enc.wpa) && L.toArray(enc.authentication).filter(function(a) { return a == 'psk' }).length > 0),
-                           is_sae = (enc && Array.isArray(enc.wpa) && L.toArray(enc.authentication).filter(function(a) { return a == 'sae' }).length > 0);
+                       const nameopt = L.toArray(form.lookupOption('name', '_new_'))[0];
+                       const passopt = L.toArray(form.lookupOption('password', '_new_'))[0];
+                       const ssidopt = L.toArray(form.lookupOption('ssid', '_new_'))[0];
+                       const bssidopt = L.toArray(form.lookupOption('bssid', '_new_'))[0];
+                       const zoneopt = L.toArray(form.lookupOption('zone', '_new_'))[0];
+                       const replopt = L.toArray(form.lookupOption('replace', '_new_'))[0];
+                       const nameval = (nameopt && nameopt.isValid('_new_')) ? nameopt.formvalue('_new_') : null;
+                       const passval = (passopt && passopt.isValid('_new_')) ? passopt.formvalue('_new_') : null;
+                       const ssidval = (ssidopt && ssidopt.isValid('_new_')) ? ssidopt.formvalue('_new_') : null;
+                       const bssidval = (bssidopt && bssidopt.isValid('_new_')) ? bssidopt.formvalue('_new_') : null;
+                       const zoneval = zoneopt ? zoneopt.formvalue('_new_') : null;
+                       const enc = L.isObject(bss.encryption) ? bss.encryption : null;
+                       const is_wep = (enc && Array.isArray(enc.wep));
+                       const is_psk = (enc && Array.isArray(enc.wpa) && L.toArray(enc.authentication).filter(function(a) { return a == 'psk' }).length > 0);
+                       const is_sae = (enc && Array.isArray(enc.wpa) && L.toArray(enc.authentication).filter(function(a) { return a == 'sae' }).length > 0);
 
                        if (nameval == null || (passopt && passval == null))
                                return;
 
-                       var section_id = null;
+                       let section_id = null;
 
                        return this.map.save(function() {
-                               var wifi_sections = uci.sections('wireless', 'wifi-iface');
+                               const wifi_sections = uci.sections('wireless', 'wifi-iface');
 
                                if (replopt.formvalue('_new_') == '1') {
-                                       for (var i = 0; i < wifi_sections.length; i++)
-                                               if (wifi_sections[i].device == radioDev.getName())
-                                                       uci.remove('wireless', wifi_sections[i]['.name']);
+                                       for (let ws of wifi_sections)
+                                               if (ws.device == radioDev.getName())
+                                                       uci.remove('wireless', ws['.name']);
                                }
 
                                if (uci.get('wireless', radioDev.getName(), 'disabled') == '1') {
-                                       for (var i = 0; i < wifi_sections.length; i++)
-                                               if (wifi_sections[i].device == radioDev.getName())
-                                                       uci.set('wireless', wifi_sections[i]['.name'], 'disabled', '1');
+                                       for (let ws of wifi_sections)
+                                               if (ws.device == radioDev.getName())
+                                                       uci.set('wireless', ws['.name'], 'disabled', '1');
 
                                        uci.unset('wireless', radioDev.getName(), 'disabled');
                                }
 
-                               var htmodes = radioDev.getHTModes();
+                               const htmodes = radioDev.getHTModes();
 
                                if (bss.vht_operation && htmodes && htmodes.indexOf('VHT20') !== -1) {
-                                       for (var w = bss.vht_operation.channel_width; w >= 20; w /= 2) {
+                                       for (let w = bss.vht_operation.channel_width; w >= 20; w /= 2) {
                                                if (htmodes.indexOf('VHT'+w) !== -1) {
                                                        uci.set('wireless', radioDev.getName(), 'htmode', 'VHT'+w);
                                                        break;
@@ -2167,7 +2134,7 @@ return view.extend({
                                        }
                                }
                                else if (bss.ht_operation && htmodes && htmodes.indexOf('HT20') !== -1) {
-                                       var w = (bss.ht_operation.secondary_channel_offset == 'no secondary') ? 20 : 40;
+                                       const w = (bss.ht_operation.secondary_channel_offset == 'no secondary') ? 20 : 40;
                                        uci.set('wireless', radioDev.getName(), 'htmode', 'HT'+w);
                                }
                                else {
@@ -2201,7 +2168,7 @@ return view.extend({
                                        uci.set('wireless', section_id, 'key', passval);
                                }
                                else if (is_psk) {
-                                       for (var i = enc.wpa.length - 1; i >= 0; i--) {
+                                       for (let i = enc.wpa.length - 1; i >= 0; i--) {
                                                if (enc.wpa[i] == 2) {
                                                        uci.set('wireless', section_id, 'encryption', 'psk2');
                                                        break;
@@ -2226,7 +2193,7 @@ return view.extend({
                                return network.addNetwork(nameval, { proto: 'dhcp' }).then(function(net) {
                                        firewall.deleteNetwork(net.getName());
 
-                                       var zonePromise = zoneval
+                                       const zonePromise = zoneval
                                                ? firewall.getZone(zoneval).then(function(zone) { return zone || firewall.addZone(zoneval) })
                                                : Promise.resolve();
 
@@ -2245,19 +2212,19 @@ return view.extend({
                s.handleJoin = function(radioDev, bss, ev) {
                        poll.remove(this.pollFn);
 
-                       var m2 = new form.Map('wireless'),
-                           s2 = m2.section(form.NamedSection, '_new_'),
-                           enc = L.isObject(bss.encryption) ? bss.encryption : null,
-                           is_wep = (enc && Array.isArray(enc.wep)),
-                           is_psk = (enc && Array.isArray(enc.wpa) && L.toArray(enc.authentication).filter(function(a) { return a == 'psk' || a == 'sae' })),
-                           replace, passphrase, name, bssid, zone;
+                       const m2 = new form.Map('wireless');
+                       const s2 = m2.section(form.NamedSection, '_new_');
+                       const enc = L.isObject(bss.encryption) ? bss.encryption : null;
+                       const is_wep = (enc && Array.isArray(enc.wep));
+                       const is_psk = (enc && Array.isArray(enc.wpa) && L.toArray(enc.authentication).filter(function(a) { return a == 'psk' || a == 'sae' }));
+                       let replace, passphrase, name, bssid, zone;
 
-                       var nameUsed = function(name) {
-                               var s = uci.get('network', name);
+                       function nameUsed(name) {
+                               const s = uci.get('network', name);
                                if (s != null && s['.type'] != 'interface')
                                        return true;
 
-                               var net = (s != null) ? network.instantiateNetwork(name) : null;
+                               const net = (s != null) ? network.instantiateNetwork(name) : null;
                                return (net != null && !net.isEmpty());
                        };
 
@@ -2288,7 +2255,7 @@ return view.extend({
                                return true;
                        };
 
-                       for (var i = 2; nameUsed(name.default); i++)
+                       for (let i = 2; nameUsed(name.default); i++)
                                name.default = 'wwan%d'.format(i);
 
                        if (is_wep || is_psk) {
@@ -2324,7 +2291,7 @@ return view.extend({
                };
 
                s.handleAdd = function(radioDev, ev) {
-                       var section_id = next_free_sid(uci.sections('wireless', 'wifi-iface').length);
+                       const section_id = next_free_sid(uci.sections('wireless', 'wifi-iface').length);
 
                        uci.unset('wireless', radioDev.getName(), 'disabled');
 
@@ -2341,8 +2308,8 @@ return view.extend({
                o = s.option(form.DummyValue, '_badge');
                o.modalonly = false;
                o.textvalue = function(section_id) {
-                       var inst = this.section.lookupRadioOrNetwork(section_id),
-                           node = E('div', { 'class': 'center' });
+                       const inst = this.section.lookupRadioOrNetwork(section_id);
+                       const node = E('div', { 'class': 'center' });
 
                        if (inst.getWifiNetworks)
                                node.appendChild(render_radio_badge(inst));
@@ -2355,7 +2322,7 @@ return view.extend({
                o = s.option(form.DummyValue, '_stat');
                o.modalonly = false;
                o.textvalue = function(section_id) {
-                       var inst = this.section.lookupRadioOrNetwork(section_id);
+                       const inst = this.section.lookupRadioOrNetwork(section_id);
 
                        if (inst.getWifiNetworks)
                                return render_radio_status(inst, this.section.wifis.filter(function(e) {
@@ -2367,17 +2334,16 @@ return view.extend({
 
                return m.render().then(L.bind(function(m, nodes) {
                        poll.add(L.bind(function() {
-                               var section_ids = m.children[0].cfgsections(),
-                                   tasks = [ network.getHostHints(), network.getWifiDevices() ];
+                               const tasks = [ network.getHostHints(), network.getWifiDevices() ];
 
-                               for (var i = 0; i < section_ids.length; i++) {
-                                       var row = nodes.querySelector('.cbi-section-table-row[data-sid="%s"]'.format(section_ids[i])),
-                                           dsc = row.querySelector('[data-name="_stat"] > div'),
-                                           btns = row.querySelectorAll('.cbi-section-actions button');
+                               m?.children[0]?.cfgsections?.().forEach(s => {
+                                       const row = nodes.querySelector('.cbi-section-table-row[data-sid="%s"]'.format(s));
+                                       const dsc = row.querySelector('[data-name="_stat"] > div');
+                                       const btns = row.querySelectorAll('.cbi-section-actions button');
 
                                        if (dsc.getAttribute('restart') == '') {
                                                dsc.setAttribute('restart', '1');
-                                               tasks.push(fs.exec('/sbin/wifi', ['up', section_ids[i]]).catch(function(e) {
+                                               tasks.push(fs.exec('/sbin/wifi', ['up', s]).catch(function(e) {
                                                        ui.addNotification(null, E('p', e.message));
                                                }));
                                        }
@@ -2386,39 +2352,37 @@ return view.extend({
                                                btns[0].classList.remove('spinning');
                                                btns[0].disabled = false;
                                        }
-                               }
+                               });
 
                                return Promise.all(tasks)
                                        .then(L.bind(function(hosts_radios) {
-                                               var tasks = [];
+                                               const tasks = [];
 
-                                               for (var i = 0; i < hosts_radios[1].length; i++)
-                                                       tasks.push(hosts_radios[1][i].getWifiNetworks());
+                                               hosts_radios[1].forEach(r => tasks.push(r.getWifiNetworks()) );
 
                                                return Promise.all(tasks).then(function(data) {
                                                        hosts_radios[2] = [];
 
-                                                       for (var i = 0; i < data.length; i++)
-                                                               hosts_radios[2].push.apply(hosts_radios[2], data[i]);
+                                                       for (let d of data)
+                                                               hosts_radios[2].push.apply(hosts_radios[2], d);
 
                                                        return hosts_radios;
                                                });
                                        }, network))
                                        .then(L.bind(function(hosts_radios_wifis) {
-                                               var tasks = [];
+                                               const tasks = [];
 
-                                               for (var i = 0; i < hosts_radios_wifis[2].length; i++)
-                                                       tasks.push(hosts_radios_wifis[2][i].getAssocList());
+                                               hosts_radios_wifis[2].forEach(hrw => tasks.push(hrw.getAssocList()) );
 
                                                return Promise.all(tasks).then(function(data) {
                                                        hosts_radios_wifis[3] = [];
 
-                                                       for (var i = 0; i < data.length; i++) {
-                                                               var wifiNetwork = hosts_radios_wifis[2][i],
-                                                                   radioDev = hosts_radios_wifis[1].filter(function(d) { return d.getName() == wifiNetwork.getWifiDeviceName() })[0];
+                                                       for (let i = 0; i < data.length; i++) {
+                                                               const wifiNetwork = hosts_radios_wifis[2][i];
+                                                               const radioDev = hosts_radios_wifis[1].filter(function(d) { return d.getName() == wifiNetwork.getWifiDeviceName() })[0];
 
-                                                               for (var j = 0; j < data[i].length; j++)
-                                                                       hosts_radios_wifis[3].push(Object.assign({ radio: radioDev, network: wifiNetwork }, data[i][j]));
+                                                               for (let dy of data[i])
+                                                                       hosts_radios_wifis[3].push(Object.assign({ radio: radioDev, network: wifiNetwork }, dy));
                                                        }
 
                                                        return hosts_radios_wifis;
@@ -2431,7 +2395,7 @@ return view.extend({
                                        .then(L.bind(this.poll_status, this, nodes));
                        }, this), 5);
 
-                       var table = E('table', { 'class': 'table assoclist', 'id': 'wifi_assoclist_table' }, [
+                       const table = E('table', { 'class': 'table assoclist', 'id': 'wifi_assoclist_table' }, [
                                E('tr', { 'class': 'tr table-titles' }, [
                                        E('th', { 'class': 'th nowrap' }, _('Network')),
                                        E('th', { 'class': 'th hide-xs' }, _('MAC address')),